﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Linq;

namespace MoodLaZik.Model
{
    public class XmlManipulator
    {
        #region Fields
        public static String _dirpath = @"C:\Users\Public\Music";
        public static String _lastmodifiedDir = @"C:\Users\Public\lastmodified.txt";
        public static String _moodvsTypeXML = @"C:\Users\Public\Music\moodvsTypeXML.xml";
        public static String _placevsTypeXML = @"C:\Users\Public\Music\placevsTypeXML.xml";
        public static String _weathervsTypeXML = @"C:\Users\Public\Music\weathervsTypeXML.xml";
        public static String _personnalityvsTypeXML = @"C:\Users\Public\Music\personnalityvsTypeXML.xml";
        public static String _environmentvsTypeXML = @"C:\Users\Public\Music\environmentvsTypeXML.xml";
        public static String _agentBrainXML = @"C:\Users\Public\Music\agentBrainXML.xml";
        public static String _dirtxt = @"C:\Users\Public\Music\Dirpath.txt";
        public static Dictionary<String, String> _infos, _backup;
        public static long _lastmodified;
        #endregion

        #region Properties
        
        #endregion

        #region Functions

            public bool CheckXmlFiles()
            {
                return ((!File.Exists(_moodvsTypeXML) ||
                    !File.Exists(_environmentvsTypeXML) ||
                    !File.Exists(_personnalityvsTypeXML) ||
                    !File.Exists(_placevsTypeXML) ||
                    !File.Exists(_weathervsTypeXML) ||
                    !File.Exists(_agentBrainXML)) ? (false) : (true));
            }

            public void SaveLastModified()
            {
                System.IO.StreamWriter file = new System.IO.StreamWriter(_lastmodifiedDir);
                file.WriteLine(_lastmodified.ToString());
                file.Close();
            }

            public void SaveDirPath()
            {
                System.IO.StreamWriter file = new System.IO.StreamWriter(_dirtxt);
                _lastmodified = File.GetCreationTime(_dirtxt).Ticks;
                SaveLastModified();
                file.WriteLine(_dirpath);
                file.Close();
            }

            public bool IsDirPathChanged()
            {
                if (!File.Exists(_dirtxt)) return false;
                if (_lastmodified == 0)
                {
                    String tmp = String.Empty;
                    GetDirLastModified(ref tmp);
                    _lastmodified = long.Parse(tmp);
                }
                long dt = new long();
                try
                {
                    dt = File.GetLastWriteTime(_dirtxt).Ticks;
                }
                catch (Exception e) {}
                if (dt != _lastmodified)
                {
                    _lastmodified = dt;
                    SaveLastModified();
                    return true;
                }
                return false;
            }

            public void GetDirLastModified(ref String mystr)
            {
                if (!File.Exists(_lastmodifiedDir)) return ;
                StreamReader sr = new StreamReader(_lastmodifiedDir);
                String s = sr.ReadToEnd();
                if (String.IsNullOrWhiteSpace(s)) { sr.Close(); return ; }
                mystr = s;
            }

            public bool GetDirPathSaved(ref String dirpathsaved)
            {
                if (!File.Exists(_dirtxt)) return false;
                StreamReader sr = new StreamReader(_dirtxt);
                dirpathsaved = sr.ReadToEnd();
                if (String.IsNullOrWhiteSpace(dirpathsaved)) { sr.Close(); return false; }
                sr.Close();
                return true;
            }

            public void BackUpAgentBrain(Dictionary<String, String> infos, ref List<String> songtitles)
            {
                XDocument xmlDoc = XDocument.Load(_agentBrainXML);
                List<XElement> q = (from c in xmlDoc.Descendants("Sub")
                                    where c.Attribute("MOOD").Value == infos["MOOD"] &&
                                    c.Attribute("PLACE").Value == infos["PLACE"] &&
                                    c.Attribute("WEATHER").Value == infos["WEATHER"] &&
                                    c.Attribute("ENVIRONMENT").Value == infos["ENVIRONMENT"] &&
                                    c.Attribute("PERSONNALITY").Value == infos["PERSONNALITY"] &&
                                    c.Attribute("HOUR").Value == infos["HOUR"]
                                    select c).ToList();
                if (q.Count() != 0)
                {
                    String tmp = String.Empty;
                    foreach (XElement elem in q[0].Elements())
                    {
                        tmp = Path.GetFileNameWithoutExtension(elem.Value);
                        songtitles.Add(tmp);
                    }
                }
            }

            public void CreateMoodvsTypeXMLFile()
            {
                using (XmlWriter writer = XmlWriter.Create(_moodvsTypeXML))
                {
                    writer.WriteStartElement("MoodvsTypeXMLFile");
                    writer.WriteElementString("HAPPY", "HIP-HOP/RAP/DANCE/PUNK/ROCK/ALTERNATIVE");
                    writer.WriteElementString("SAD", "COUNTRY/CLASSICAL");
                    writer.WriteElementString("ANGRY", "RAP/HIP HOP");
                    writer.WriteElementString("SLEEPY", "CLASSICAL");
                    writer.WriteElementString("FUNKY", "RAP/DANCE/PUNK/ROCK");
                    writer.WriteElementString("DRIVING", "COUNTRY");
                    writer.WriteElementString("WORKING", "CLASSICAL");
                    writer.WriteElementString("MELANCHOLY", "CLASSICAL");
                    writer.WriteElementString("NOSTALGY", "COUNTRY");
                    writer.WriteElementString("AGGRESSIVE", "HIP-HOP/RAP/HEAVY METAL");
                    writer.WriteElementString("SUICIDAL", "COUNTRY");
                    writer.WriteElementString("ROMANTIC", "JAZZ/CLASSICAL");
                    writer.WriteElementString("CHILLOUT", "CLASSICAL");
                    writer.WriteElementString("CALM", "CLASSICAL");
                    writer.WriteEndElement();
                    writer.Close();
                }
            }

            public void CreatePlacevsTypeXMLFile()
            {
                using (XmlWriter writer = XmlWriter.Create(_placevsTypeXML))
                {
                    writer.WriteStartElement("PlacevsTypeXMLFile");
                    writer.WriteElementString("HOME", "ACID/ALTERNATIVE/POWER-POP/ROCK/EMO/COUNTRY/SATIRE/BREAKBEAT/DANCE/DISCO/ELECTRONIC/FUNK/HIP-HOP/JAZZ");
                    writer.WriteElementString("SUBWAY", "ACID/ALTERNATIVE/POWER-POP/ROCK/EMO/COUNTRY/SATIRE/BREAKBEAT/DANCE/DISCO/ELECTRONIC/FUNK/HIP-HOP/JAZZ");
                    writer.WriteElementString("WORK", "SOUL/COUNTRY/ZOUK/SOFT ROCK/RAP/BALLAD/CLASSICAL/EASY LISTENNING/OPERA/NEW WAVE");
                    writer.WriteElementString("SCHOOL", "FOLK/SOUL/RAP/HIP-HOP/EMO/RAP FR/RNB/ROCK/POP/WORLD MUSIC/REGGAE");
                    writer.WriteElementString("OUTSIDE", "FOLK/SOUL/RAP/HIP-HOP/EMO/RAP FR/RNB/ROCK/POP/WORLD MUSIC/REGGAE");
                    writer.WriteEndElement();
                    writer.Close();
                }
            }

            public void CreateWeathervsTypeXMLFile()
            {
                using (XmlWriter writer = XmlWriter.Create(_weathervsTypeXML))
                {
                    writer.WriteStartElement("WeathervsTypeXMLFile");
                    writer.WriteElementString("SUNNY", "ACID/ALTERNATIVE/POWER-POP/ROCK/EMO/COUNTRY/SATIRE/BREAKBEAT/DANCE/DISCO/ELECTRONIC/FUNK/HIP-HOP/JAZZ");
                    writer.WriteElementString("RAINY", "NEW AGE/ABIENT/EASY LISTENING/FOLK/EMO/INDIE/ACOUSTIC/ACOUSTIC ROCK/POP");
                    writer.WriteElementString("CLOUDY", "ALTERNATIVE/AMERICANA/FOLK/INDIE");
                    writer.WriteElementString("FOGGY", "ALTERNATIVE/AMERICANA/FOLK/INDIE");
                    writer.WriteElementString("STORMY", "NEW AGE/ABIENT/EASY LISTENING/FOLK/EMO/INDIE/ACOUSTIC/ACOUSTIC ROCK/POP");
                    writer.WriteElementString("WARMY", "REGGAE/JAZZ/ROCK/HIP-HOP/FUNK/DANCEHALL/RNB");
                    writer.WriteEndElement();
                    writer.Close();
                }
            }

            public void CreatePersonnalityvsTypeXMLFile()
            {
                using (XmlWriter writer = XmlWriter.Create(_personnalityvsTypeXML))
                {
                    writer.WriteStartElement("PersonnalityvsTypeXMLFile");
                    writer.WriteElementString("AGGRESSIVE", "COUNTRY/RAP/SOFT ROCK/ACID/ALTERNATIVE/ELECTRONIC/CLASSICAL");
                    writer.WriteElementString("SUICIDAL", "COUNTRY/RAP/SOFT ROCK/ACID/ALTERNATIVE/ELECTRONIC/CLASSICAL");
                    writer.WriteElementString("INTROVERTED", "ACCOUSTIC ROCK/EASY LISTENING/ROCK/POP/FOLK/SOUL/CLASSICAL/ZOUK/SOFT ROCK/RAP/RAP FR/HIP-HOP/RNB");
                    writer.WriteElementString("EXTRAVERTED", "POP/HOUSE MUSIC/ACID JAZZ/ELECTRONIC/NEW AGE");
                    writer.WriteEndElement();
                    writer.Close();
                }
            }

            public void CreateEnvironmentvsTypeXMLFile()
            {
                using (XmlWriter writer = XmlWriter.Create(_environmentvsTypeXML))
                {
                    writer.WriteStartElement("EnvironmentvsTypeXMLFile");
                    writer.WriteElementString("SILENT", "OPERA/CONTEMPORARY CHRISTIAN MUSIC/SPIRITUAL/ZOUK/COUNTRY/SOFT ROCK");
                    writer.WriteElementString("NOISY", "SOFT ROCK/ACID/ALTERNATIVE/ELECTRONIC/CLASSICAL");
                    writer.WriteElementString("CALM", "SOUL/CONTEMPORARY CHRISTIAN MUSIC/SPIRITUAL/ZOUK/COUNTRY/SOFT ROCK/OPERA");
                    writer.WriteElementString("SPIRITUAL", "SOUL/OPERA/SPIRITUAL/COUNTRY/CONTEMPORARY CHRISTIAN MUSIC/SOFT ROCK");
                    writer.WriteElementString("FAMILIAL", "ACID/ALTERNATIVE/POWER-POP/ROCK/EMO/COUNTRY/SATIRE/BREAKBEAT/DANCE/DISCO/ELECTRONIC/FUNK/HIP-HOP/JAZZ");
                    writer.WriteElementString("URBAN", "RAP/HIP-HOP/EMO/RAP FR/RNB/ROCK/POP");
                    writer.WriteEndElement();
                    writer.Close();
                }
            }

            private void ProcessInfos(ref String infos, Dictionary<String, String> moodvstype)
            {
                char[] delimiterChars = { '/', ':' };
                string[] words = infos.Split(delimiterChars);
                for (int i = 0; i < words.Length; i += 2)
                    moodvstype.Add(words[i], words[i + 1]);
            }

            public void SetHoursFormat(ref String hourrange)
            {
                DateTime mydate = DateTime.Now;
                int nb, min, max;

                nb = min = max = -1;
                nb = mydate.TimeOfDay.Hours;
                if (nb >= 0)
                {
                    if (nb % 2 != 0) { min = nb - 1; max = nb + 1; }
                    else { min = nb; max = nb + 2; }
                    hourrange = Convert.ToString(min) + "-" + Convert.ToString(max);
                }
            }

            public void CreateAgentBrainXMLFile()
            {
                if (!File.Exists(_agentBrainXML))
                {
                    using (XmlWriter writer = XmlWriter.Create(_agentBrainXML))
                    {
                        writer.WriteStartElement("AgentBrainXMLFile");
                        writer.WriteEndElement();
                        writer.Close();
                    }
                }
            }

            public void RemoveSongtitleFromAgentBrain(Dictionary<String, String> infos, String songtitle)
            {
                XDocument xmlDoc = XDocument.Load(_agentBrainXML);
                List<XElement> q = (from c in xmlDoc.Descendants("Sub")
                                    where c.Attribute("MOOD").Value == infos["MOOD"] &&
                                    c.Attribute("PLACE").Value == infos["PLACE"] &&
                                    c.Attribute("WEATHER").Value == infos["WEATHER"] &&
                                    c.Attribute("ENVIRONMENT").Value == infos["ENVIRONMENT"] &&
                                    c.Attribute("PERSONNALITY").Value == infos["PERSONNALITY"] &&
                                    c.Attribute("HOUR").Value == infos["HOUR"]
                                    select c).ToList();

                if (q.Count() == 0) return;
                else
                {
                    songtitle += ".mp3";
                    List<XElement> ans = (from element in q[0].Elements()
                                          where element.Value.EndsWith(songtitle) == true
                                          select element).ToList();
                    if (ans.Count() != 0) ans[0].Remove();
                    xmlDoc.Save(_agentBrainXML);
                }
            }

            private bool CheckIfSongTitleFieldAlreadyExist(Dictionary<String, String> infos, String songtitle)
            {
                XDocument xmlDoc = XDocument.Load(_agentBrainXML);
                List<XElement> q = (from c in xmlDoc.Descendants("Sub")
                                    where c.Attribute("MOOD").Value == infos["MOOD"] &&
                                    c.Attribute("PLACE").Value == infos["PLACE"] &&
                                    c.Attribute("WEATHER").Value == infos["WEATHER"] &&
                                    c.Attribute("ENVIRONMENT").Value == infos["ENVIRONMENT"] &&
                                    c.Attribute("PERSONNALITY").Value == infos["PERSONNALITY"] &&
                                    c.Attribute("HOUR").Value == infos["HOUR"]
                                    select c).ToList();

                if (q.Count() == 0) return false;
                else
                {
                    foreach (XElement elem in q[0].Elements())
                    {
                        if (elem.Value == songtitle) return true;
                    }
                    return false;
                }
            }

            public bool AddFieldsInAgentBrainOldSub(Dictionary<String, String> infos, List<String> songtitles, String tag)
            {
                XDocument xmlDoc = XDocument.Load(_agentBrainXML);
                List<XElement> q = (from c in xmlDoc.Descendants("Sub")
                                    where c.Attribute("MOOD").Value == infos["MOOD"] &&
                                    c.Attribute("PLACE").Value == infos["PLACE"] &&
                                    c.Attribute("WEATHER").Value == infos["WEATHER"] &&
                                    c.Attribute("ENVIRONMENT").Value == infos["ENVIRONMENT"] &&
                                    c.Attribute("PERSONNALITY").Value == infos["PERSONNALITY"] &&
                                    c.Attribute("HOUR").Value == infos["HOUR"]
                                    select c).ToList();

                if (q.Count() != 0)
                {
                    foreach (String str in songtitles)
                    {
                        if (!CheckIfSongTitleFieldAlreadyExist(infos, str) && FindInterestingAudioType(tag, str))
                        {
                            var newsong = new XElement("SongTitle", str);
                            q[0].Add(newsong);
                            xmlDoc.Save(_agentBrainXML);
                        }
                    }
                    return true;
                }
                return false;
            }

            public void AddNewFieldsInAgentBrainXMLFile(ref Dictionary<String, String> moodvstype, ref List<String> songtitles, String tag)
            {
                if (AddFieldsInAgentBrainOldSub(moodvstype, songtitles, tag)) return;
                XmlDocument originalXml = new XmlDocument();
                originalXml.Load(_agentBrainXML);
                XmlNode menu = originalXml.SelectSingleNode("AgentBrainXMLFile");
                XmlNode Sub = originalXml.CreateNode(XmlNodeType.Element, "Sub", null);
                foreach (KeyValuePair<String, String> mt in moodvstype)
                {
                    XmlAttribute att = originalXml.CreateAttribute(mt.Key);
                    att.Value = mt.Value;
                    Sub.Attributes.Append(att);
                }
                foreach (String str in songtitles)
                {
                    if (!CheckIfSongTitleFieldAlreadyExist(moodvstype, str) && FindInterestingAudioType(tag, str))
                    {
                        XmlElement SongTitle = originalXml.CreateElement("SongTitle");
                        SongTitle.InnerText = str;
                        if (SongTitle != null) Sub.AppendChild(SongTitle);
                    }
                }
                if (Sub != null && menu != null)
                    menu.AppendChild(Sub);
                originalXml.Save(_agentBrainXML);
            }

            private void fillPart(int src, out String str)
            {
                str = String.Empty;
                if (src < 10)
                    str = "0" + src;
                else
                    str = str + src;
            }

            private void getLength(TimeSpan src, out String str)
            {
                str = String.Empty;
                String hours, minutes, seconds, sep;
                fillPart(src.Hours, out hours);
                fillPart(src.Minutes, out minutes);
                fillPart(src.Seconds, out seconds);
                sep = ":";
                str = (src.Hours != 0) ? (str + hours + sep) : (str + minutes);
                str = str + sep + seconds;
            }

            private void getContent(String[] strtab, out String str)
            {
                int len = strtab.Length;
                str = String.Empty;
                for (int i = 0; i < len; ++i)
                {
                    str = str + strtab[i];
                    if (i + 1 < len && !(String.IsNullOrEmpty(strtab[i + 1])))
                        str = str + ", ";
                }
            }

            public bool FindInterestingAudioType(String infos, String fullpath)
            {
                char[] delimiterChars = { '/' };
                string[] words = infos.Split(delimiterChars);
                if (CheckFileCharacteristics(fullpath))
                {
                    TagLib.File file = TagLib.File.Create(fullpath);
                    String tmpstr = String.Empty;
                    this.getContent(file.Tag.Genres, out tmpstr);
                    tmpstr = tmpstr.ToUpper();
                    foreach(string str in words)
                    {
                        if (tmpstr == str) return true;
                    }
                }
                return false;
            }

            public void getAudioCharacteristics(Dictionary<String, String> infos, String Filename, ref List<String> mytab)
            {
                List<String> ans;
                XDocument xmlDoc = XDocument.Load(_agentBrainXML);
                List<XElement> q = (from c in xmlDoc.Descendants("Sub")
                                    where c.Attribute("MOOD").Value == infos["MOOD"] &&
                                    c.Attribute("PLACE").Value == infos["PLACE"] &&
                                    c.Attribute("WEATHER").Value == infos["WEATHER"] &&
                                    c.Attribute("ENVIRONMENT").Value == infos["ENVIRONMENT"] &&
                                    c.Attribute("PERSONNALITY").Value == infos["PERSONNALITY"] &&
                                    c.Attribute("HOUR").Value == infos["HOUR"]
                                    select c).ToList();

                if (q.Count() == 0) return;
                else
                {
                    Filename += ".mp3";
                    ans = (from element in q[0].Elements()
                                  where element.Value.EndsWith(Filename) == true
                                  select element.Value).ToList();
                }
                if (ans.Count() == 0) return;
                TagLib.File file = TagLib.File.Create(ans[0]);
                String tmpstr = String.Empty;
                mytab.Add(file.Tag.Title);
                this.getLength(file.Properties.Duration, out tmpstr);
                mytab.Add(tmpstr);
                this.getContent(file.Tag.Genres, out tmpstr);
                mytab.Add(tmpstr);
            }

            public bool CheckFileCharacteristics(String FileFullPath)
            {
                try
                {
                    TagLib.File file = TagLib.File.Create(FileFullPath);
                    return (file.Properties.MediaTypes == TagLib.MediaTypes.Audio) ? (true) : (false);
                }
                catch (TagLib.UnsupportedFormatException) {}
                return true;
            }
        #endregion

        #region Ctor
        public XmlManipulator()
        {
            _infos = _backup = new Dictionary<String, String>();
            _lastmodified = new long();
        }
        #endregion
    }
}
